package bean.managed;

import entity.BackorderEntity;
import bean.managed.util.JsfUtil;
import bean.managed.util.PaginationHelper;
import bean.session.BackorderEntityFacade;

import bean.session.SalesOrderEntityFacade;
import entity.DepartmentEntity;
import entity.MrpToQuantityEntity;
import entity.ProductQuantityPriceEntity;
import entity.SalesOrderEntity;
import entity.SystemUserEntity;
import java.io.Serializable;
import java.text.Format;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collection;
import java.util.ResourceBundle;
import javax.ejb.EJB;
import javax.faces.application.FacesMessage;
import javax.faces.application.ViewHandler;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ManagedProperty;
import javax.faces.bean.SessionScoped;
import javax.faces.component.UIComponent;
import javax.faces.component.UIInput;
import javax.faces.component.UIViewRoot;
import javax.faces.context.FacesContext;
import javax.faces.convert.Converter;
import javax.faces.convert.FacesConverter;
import javax.faces.event.ComponentSystemEvent;
import javax.faces.model.DataModel;
import javax.faces.model.ListDataModel;
import javax.faces.model.SelectItem;
import javax.faces.validator.ValidatorException;
import managedbean.AbstractBacking;
import org.primefaces.event.DateSelectEvent;
import type.BackorderStatus;
import type.InternalStatus;
import util.Fixtures.Department;

@ManagedBean(name = "backorderEntityController")
@SessionScoped
public class BackorderEntityController extends AbstractBacking implements Serializable {

    private BackorderEntity current;
    private DataModel items = null;
    @EJB
    private bean.session.BackorderEntityFacade ejbFacade;
    @EJB
    private bean.session.RawMaterialEntityFacade materialFacade;
    @EJB
    private bean.session.DepartmentEntityFacade departmentFacade;
    @EJB
    private SalesOrderEntityFacade salesOrderFacade;
    
    private PaginationHelper pagination;
    private int selectedItemIndex;
    private int pqpListSize;
    private Format formatter = new SimpleDateFormat("dd/MM/yyyy");
    @ManagedProperty(value = "#{systemMessageController}")
    private SystemMessageController systemMessageController;
//    private ArrayList<MrpToQuantityEntity>updatedMrps = new ArrayList<MrpToQuantityEntity>();
    @ManagedProperty(value = "#{salesOrderEntityController}")
    SalesOrderEntityController salesOrderEntityController;
    @ManagedProperty(value = "#{completedGoodsEntityController}")
    CompletedGoodsEntityController completedGoodsEntityController;
    @ManagedProperty(value = "#{productQuantityPriceEntityController}")
    ProductQuantityPriceEntityController productQuantityPriceEntityController;
    private boolean backorderEdit;
    int pqp1Quantity;
    double pqp1Price;
    int pqp2Quantity;
    double pqp2Price;
    int pqp3Quantity;
    double pqp3Price;
    int pqp4Quantity;
    double pqp4Price;
    public boolean inEdit;

    public BackorderEntityController() {
    }

    public Format getFormatter() {
        return formatter;
    }

    public void setFormatter(Format mat) {
        formatter = mat;
    }

    public BackorderStatus[] getBackorderStatus() {
        return BackorderStatus.values();
    }

    public void editBackorder() {
        this.getFacade().edit(current);
        this.setBackorderEdit(!backorderEdit);
    }

    public boolean isBackorderEdit() {
        return backorderEdit;
    }

    public void setBackorderEdit(boolean backorderEdit) {
        this.backorderEdit = backorderEdit;
    }

    public void dateSelect(DateSelectEvent event) {
        this.getFacade().edit(current);
    }

    public double getPqp2Price() {
        return pqp2Price;
    }

    public void setPqp2Price(double pqp2Price) {
        this.pqp2Price = pqp2Price;
    }

    public int getPqp2Quantity() {
        return pqp2Quantity;
    }

    public void setPqp2Quantity(int pqp2Quantity) {
        this.pqp2Quantity = pqp2Quantity;
    }

    public double getPqp3Price() {
        return pqp3Price;
    }

    public void setPqp3Price(double pqp3Price) {
        this.pqp3Price = pqp3Price;
    }

    public int getPqp3Quantity() {
        return pqp3Quantity;
    }

    public void setPqp3Quantity(int pqp3Quantity) {
        this.pqp3Quantity = pqp3Quantity;
    }

    public double getPqp4Price() {
        return pqp4Price;
    }

    public void setPqp4Price(double pqp4Price) {
        this.pqp4Price = pqp4Price;
    }

    public int getPqp4Quantity() {
        return pqp4Quantity;
    }

    public void setPqp4Quantity(int pqp4Quantity) {
        this.pqp4Quantity = pqp4Quantity;
    }

    public double getPqp1Price() {
        return pqp1Price;
    }

    public void setPqp1Price(double pqp1Price) {
        this.pqp1Price = pqp1Price;
    }

    public int getPqp1Quantity() {
        return pqp1Quantity;
    }

    public void setPqp1Quantity(int pqp1Quantity) {
        this.pqp1Quantity = pqp1Quantity;
    }

    public void editToggle() {
        this.setInEdit(!inEdit);
    }

    public boolean isInEdit() {
        return inEdit;
    }

    public void setInEdit(boolean inEdit) {
        this.inEdit = inEdit;
    }

    public int getPqpListSize() {
        if (current == null) {
            return 0;
        }
        if (current.getProductQuantityPriceList() != null) {
            pqpListSize = current.getProductQuantityPriceList().size();
            return pqpListSize;
        } else {
            return 0;
        }
    }

    public boolean isConfirmed(BackorderEntity order) {
        if (order.getStatus() == BackorderStatus.Confirmed) {
            return true;
        } else {
            return false;
        }
    }

    public boolean isCancelled(BackorderEntity order) {
        if (order.getStatus() == BackorderStatus.Cancelled) {
            return true;
        } else {
            return false;
        }
    }

    public String updateMrps() {
//        System.out.println("alalala");
        current.setStatus(BackorderStatus.Confirmed);

        current = getFacade().updateMrpPlannedOrders(current);
        System.out.println("updated");
        DepartmentEntity purchasingDp = departmentFacade.findDepartmentByName(Department.Purchasing.getName());
        SystemUserEntity purchasingManager = purchasingDp.getManager();
        String message = "BackOrder " + current.getId() + " is approved, please make extra plan orders for it";
        systemMessageController.getEjbFacade().createAndSendSystemMessage(purchasingManager,
                message, "/entities/backorderEntity/List.xhtml", systemMessageController);


        return "/entities/backorderEntity/View?faces-redirect=true";
    }

    public SystemMessageController getSystemMessageController() {
        return systemMessageController;
    }

    public void setSystemMessageController(SystemMessageController systemMessageController) {
        this.systemMessageController = systemMessageController;
    }

    public void savePqpList() {
        System.out.println("i am hereeee");
//        System.out.println("pqp qty" + pqp1.getQuantity());
        ProductQuantityPriceEntity pqp1 = new ProductQuantityPriceEntity();
        ProductQuantityPriceEntity pqp2 = new ProductQuantityPriceEntity();
        ProductQuantityPriceEntity pqp3 = new ProductQuantityPriceEntity();
        ProductQuantityPriceEntity pqp4 = new ProductQuantityPriceEntity();

        current.getProductQuantityPriceList().add(pqp1);
        pqp1.setBackorder(current);
        pqp1.setProduct(getCompletedGoodsEntityController().getEjbFacade().findCGByName("Classic Nutri Bar (Nuts)"));
        pqp1.setPrice(pqp1Price);
        pqp1.setQuantity(pqp1Quantity);

        current.getProductQuantityPriceList().add(pqp2);
        pqp2.setBackorder(current);
        pqp2.setProduct(getCompletedGoodsEntityController().getEjbFacade().findCGByName("Classic Nutri Bar (Fruits)"));
        pqp2.setPrice(pqp2Price);
        pqp2.setQuantity(pqp2Quantity);

        current.getProductQuantityPriceList().add(pqp3);
        pqp3.setBackorder(current);
        pqp3.setProduct(getCompletedGoodsEntityController().getEjbFacade().findCGByName("Premium Power Bar (Chocolate Nuts)"));
        pqp3.setPrice(pqp3Price);
        pqp3.setQuantity(pqp3Quantity);

        current.getProductQuantityPriceList().add(pqp4);
        pqp4.setBackorder(current);
        pqp4.setProduct(getCompletedGoodsEntityController().getEjbFacade().findCGByName("Premium Power Bar (Redcurrant Fruits)"));
        pqp4.setPrice(pqp4Price);
        pqp4.setQuantity(pqp4Quantity);

        this.editToggle();
        this.productQuantityPriceEntityController.getEjbFacade().create(pqp4);
        this.productQuantityPriceEntityController.getEjbFacade().create(pqp3);
        this.productQuantityPriceEntityController.getEjbFacade().create(pqp2);
        this.productQuantityPriceEntityController.getEjbFacade().create(pqp1);


        this.getFacade().edit(current);
    }

//    public void setUpdateMrps(ArrayList<MrpToQuantityEntity>list){
//        updatedMrps = list;
//    }
//    
//    public ArrayList<MrpToQuantityEntity> getUpdatedMrps(){
//        updatedMrps = new ArrayList<MrpToQuantityEntity>(current.getUpdatedAtpMrps());
//        return updatedMrps;
//    }
    public void editPqpList() {
//       List<ProductQuantityPriceEntity> pqpList = new ArrayList<ProductQuantityPriceEntity>(current.getProductQuantityPriceList());
//        for (ProductQuantityPriceEntity pqp : pqpList) {
////        for(int i=0; i<current.getProductQuantityPriceList().size(); i++){
////            //ProductQuantityPriceEntity pqp = pqpList.get(i);
//            if (pqp.getProduct().getProductName().equals("Classic Nutri Bar (Nuts)")) {
////                pqpList.get(i).setQuantity(pqp1.getQuantity());
////                pqpList.get(i).setPrice(pqp1.getPrice());
//                this.getProductQuantityPriceEntityController().getEjbFacade().edit(pqpList.get(0));
////            }
////            if (pqp.getProduct().getProductName().equals("Classic Nutri Bar (Fruits)")) {
////                pqp.setQuantity(pqp2.getQuantity());
////                pqp.setPrice(pqp2.getPrice());
//                this.getProductQuantityPriceEntityController().getEjbFacade().edit(pqpList.get(1));
////            }
////            if (pqp.getProduct().getProductName().equals("Premium Power Bar (Chocolate Nuts)")) {
////                pqp.setQuantity(pqp3.getQuantity());
////                pqp.setPrice(pqp3.getPrice());
//                this.getProductQuantityPriceEntityController().getEjbFacade().edit(pqpList.get(2));
////            }
////            if (pqp.getProduct().getProductName().equals("Premium Power Bar (Redcurrant Fruits)")) {
////                pqp.setQuantity(pqp4.getQuantity());
////                pqp.setPrice(pqp4.getPrice());
//                this.getProductQuantityPriceEntityController().getEjbFacade().edit(pqpList.get(3));
////            }
////        }
        this.getFacade().edit(current);
//        this.getProductQuantityPriceEntityController().getEjbFacade().edit(current.getProductQuantityPriceList());

        this.editToggle();
    }

    public ProductQuantityPriceEntityController getProductQuantityPriceEntityController() {
        return productQuantityPriceEntityController;
    }

    public void setProductQuantityPriceEntityController(ProductQuantityPriceEntityController productQuantityPriceEntityController) {
        this.productQuantityPriceEntityController = productQuantityPriceEntityController;
    }

    public CompletedGoodsEntityController getCompletedGoodsEntityController() {
        return completedGoodsEntityController;
    }

    public void setCompletedGoodsEntityController(CompletedGoodsEntityController completedGoodsEntityController) {
        this.completedGoodsEntityController = completedGoodsEntityController;
    }

    public void setPqpListSize(int pqpListSize) {
        this.pqpListSize = pqpListSize;
    }

    public BackorderEntity getCurrent() {
        return current;
    }

    public void setCurrent(BackorderEntity current) {
        this.current = current;
    }

    public SalesOrderEntityController getSalesOrderEntityController() {
        return salesOrderEntityController;
    }

    public void setSalesOrderEntityController(SalesOrderEntityController salesOrderEntityController) {
        this.salesOrderEntityController = salesOrderEntityController;
    }

    public BackorderEntity getSelected() {
        if (current == null) {
            current = new BackorderEntity();
            selectedItemIndex = -1;
        }
        return current;
    }

    private BackorderEntityFacade getFacade() {
        return ejbFacade;
    }

    public PaginationHelper getPagination() {
        if (pagination == null) {
            pagination = new PaginationHelper(10) {

                @Override
                public int getItemsCount() {
                    return getFacade().count();
                }

                @Override
                public DataModel createPageDataModel() {
                    return new ListDataModel(getFacade().findRange(new int[]{getPageFirstItem(), getPageFirstItem() + getPageSize()}));
                }
            };
        }
        return pagination;
    }

    public String prepareList() {
        recreateModel();
        return "/entities/backorderEntity/List?faces-redirect=true";
    }

    public String atpCheck() {
        current = (BackorderEntity) getItems().getRowData();
        Collection<MrpToQuantityEntity> list = new ArrayList<MrpToQuantityEntity>();
        current.setFailedAtpMrps(list); // initialise failed mrp list 

        current = getFacade().atpCheckForMRP(current, materialFacade.findAll(), getLoginPerson());
        current.setEarliestSopFulfillmentDate(getFacade().atpCheckForProduction(current, current.getEarliestMrpFulfillmentDate()));

        if (!current.getEarliestSopFulfillmentDate().after(current.getRequiredLeadTime())) {
            current.setConfirmedLeadTime(current.getRequiredLeadTime());
            //approve with customer ack
            //approveAtp(current);
        } else {
            current.setConfirmedLeadTime(current.getEarliestSopFulfillmentDate());
            //do smt

            DepartmentEntity salesDp = departmentFacade.findDepartmentByName(Department.Sales.getName());
            SystemUserEntity salesManager = salesDp.getManager();
            String message = "ATP for BackOrder " + current.getId() + " is done, waiting for customer review. Kindly review the shipping requests.";
            systemMessageController.getEjbFacade().createAndSendSystemMessage(salesManager,
                    message, "/entities/backorderEntity/List.xhtml", systemMessageController);
        }
        update();

        createShippingRequest();
        
        SalesOrderEntity salesOrder = current.getSalesOrder();
        salesOrder.setInternalStatus(InternalStatus.CustomerReviewPending);
        salesOrder.modified(getLoginPerson());
        salesOrderFacade.edit(salesOrder);
        
        return "/entities/backorderEntity/View?faces-redirect=true";
    }

    private void createShippingRequest() {
        if (!current.getConfirmedLeadTime().equals(current.getRequiredLeadTime())) {
            getFacade().createSecondShippingRequest(current);
        }
    }

    public String approveAtp(BackorderEntity order) {
        current = order;
//        current.setStatus(BackorderStatus.Confirmed);
        getFacade().updateMrpForBackOrder(current, materialFacade.findAll(), getLoginPerson());
        getFacade().atpForProductionApproved(current, current.getEarliestMrpFulfillmentDate());



        DepartmentEntity wareHouseDp = departmentFacade.findDepartmentByName(Department.Warehouse.getName());
        SystemUserEntity warehouseManager = wareHouseDp.getManager();
        String message = "BackOrder " + current.getId() + " is approved, please make reservations";
        systemMessageController.getEjbFacade().createAndSendSystemMessage(warehouseManager,
                message, "/entities/backorderEntity/List.xhtml", systemMessageController);

        return "/entities/backorderEntity/ApproveView?faces-redirect=true";
    }

    public String cancelOrder(BackorderEntity order) {
        getFacade().cancelTimer();
        current = order;
        current.setStatus(BackorderStatus.Cancelled);
        getFacade().cancelMrpReservationForBackOrder(current);
        getFacade().cancelReservedCapacity(current);
        DepartmentEntity wareHouseDp = departmentFacade.findDepartmentByName(Department.Warehouse.getName());
        SystemUserEntity warehouseManager = wareHouseDp.getManager();
        String message = "BackOrder " + current.getId() + " is canceled, please unreserve the stocks";
        systemMessageController.getEjbFacade().createAndSendSystemMessage(warehouseManager,
                message, "/entities/backorderEntity/List.xhtml", systemMessageController);

        return "/entities/backorderEntity/List?faces-redirect=true";
    }

    public void validatePlannedOrder(ComponentSystemEvent event) {
        UIComponent components = event.getComponent();

        UIInput planOrder = (UIInput) components.findComponent("recommendedBO");
        double planOrderQuantity = Double.valueOf(planOrder.getLocalValue().toString());
        System.out.println("planOrderQuantity is " + planOrderQuantity);

        UIInput lot = (UIInput) components.findComponent("lotSize");
        long lotSize = Long.valueOf(lot.getLocalValue().toString());


        double finalValue = planOrderQuantity % lotSize;


        if (planOrderQuantity < 0) {
            FacesMessage message = new FacesMessage();
            message.setDetail("Plan orders must not be negative number !");
            message.setSummary("Plan orders must not be negative number !");
            message.setSeverity(FacesMessage.SEVERITY_ERROR);
            throw new ValidatorException(message);
        }
        if (finalValue != 0) {
            FacesMessage message = new FacesMessage();
            message.setDetail("Plan orders must be multiple of lot size !");
            message.setSummary("Plan orders must be multiple of lot size !");
            message.setSeverity(FacesMessage.SEVERITY_ERROR);
            throw new ValidatorException(message);
        }

    }

    public String prepareView() {
        current = (BackorderEntity) getItems().getRowData();
        //selectedItemIndex = pagination.getPageFirstItem() + getItems().getRowIndex();
        return "/entities/backorderEntity/View?faces-redirect=true";
    }

    public String prepareCreate() {
        current = new BackorderEntity();
        selectedItemIndex = -1;
        return "Create";
    }

    public String create() {
        try {
            current = new BackorderEntity();
            current.setStatus(BackorderStatus.PQPCheckPending);
            SalesOrderEntity so = salesOrderEntityController.getSelected();
            current.setSalesOrder(so);
            current.setRequiredLeadTime(so.getPurchaseOrder().getPreferredLeadTime());
            ProductQuantityPriceEntity pqp = new ProductQuantityPriceEntity();
         
            current.setCreatedBy(this.getCurrentUser());
            current.getSalesOrder().setInternalStatus(InternalStatus.ProvideLeadTimePending);
            ejbFacade.create(current);
            
            so.setBackorder(current);
            System.out.println("pqp size" + current.getSalesOrder().getPurchaseOrder().getProductQuantityPrice().size());
            salesOrderFacade.edit(so);
            this.savePqpList();

//            FacesContext context = FacesContext.getCurrentInstance();
//            String viewId = context.getViewRoot().getViewId();
//            ViewHandler handler = context.getApplication().getViewHandler();
//            UIViewRoot root = handler.createView(context, viewId);
//            root.setViewId(viewId);
//            context.setViewRoot(root);
            
            DepartmentEntity productionDp = departmentFacade.findDepartmentByName(Department.ProductionPlanning.getName());
            SystemUserEntity productionManager = productionDp.getManager();
            String message = "BackOrder " + current.getId()+" is created, please perform ATP check for it"; 
            systemMessageController.getEjbFacade().createAndSendSystemMessage(productionManager,
                        message, "/entities/backorderEntity/List.xhtml", systemMessageController);   
       

            JsfUtil.addSuccessMessage(ResourceBundle.getBundle("/Bundle").getString("BackorderEntityCreated"));
            return "/entities/salesOrderEntity/View?faces-redirect=true";
        } catch (Exception e) {
            JsfUtil.addErrorMessage(e, ResourceBundle.getBundle("/Bundle").getString("PersistenceErrorOccured"));
            return null;
        }
    }

    public String prepareEdit() {
        current = (BackorderEntity) getItems().getRowData();
        selectedItemIndex = pagination.getPageFirstItem() + getItems().getRowIndex();
        return "Edit";
    }

    public String update() {
        try {
            getFacade().edit(current);
            JsfUtil.addSuccessMessage(ResourceBundle.getBundle("/Bundle").getString("BackorderEntityUpdated"));
            return "View";
        } catch (Exception e) {
            JsfUtil.addErrorMessage(e, ResourceBundle.getBundle("/Bundle").getString("PersistenceErrorOccured"));
            return null;
        }
    }

    public String destroy() {
        current = (BackorderEntity) getItems().getRowData();
        selectedItemIndex = pagination.getPageFirstItem() + getItems().getRowIndex();
        performDestroy();
        recreateModel();
        return "List";
    }

    public String destroyAndView() {
        performDestroy();
        recreateModel();
        updateCurrentItem();
        if (selectedItemIndex >= 0) {
            return "View";
        } else {
            // all items were removed - go back to list
            recreateModel();
            return "List";
        }
    }

    private void performDestroy() {
        try {
            getFacade().remove(current);
            JsfUtil.addSuccessMessage(ResourceBundle.getBundle("/Bundle").getString("BackorderEntityDeleted"));
        } catch (Exception e) {
            JsfUtil.addErrorMessage(e, ResourceBundle.getBundle("/Bundle").getString("PersistenceErrorOccured"));
        }
    }

    private void updateCurrentItem() {
        int count = getFacade().count();
        if (selectedItemIndex >= count) {
            // selected index cannot be bigger than number of items:
            selectedItemIndex = count - 1;
            // go to previous page if last page disappeared:
            if (pagination.getPageFirstItem() >= count) {
                pagination.previousPage();
            }
        }
        if (selectedItemIndex >= 0) {
            current = getFacade().findRange(new int[]{selectedItemIndex, selectedItemIndex + 1}).get(0);
        }
    }

    public DataModel getItems() {
        if (items == null) {
            items = getPagination().createPageDataModel();
        }
        return items;
    }

    private void recreateModel() {
        items = null;
        current = null;
    }

    public String next() {
        getPagination().nextPage();
        recreateModel();
        return "List";
    }

    public String previous() {
        getPagination().previousPage();
        recreateModel();
        return "List";
    }

    public SelectItem[] getItemsAvailableSelectMany() {
        return JsfUtil.getSelectItems(ejbFacade.findAll(), false);
    }

    public SelectItem[] getItemsAvailableSelectOne() {
        return JsfUtil.getSelectItems(ejbFacade.findAll(), true);
    }

    @FacesConverter(forClass = BackorderEntity.class)
    public static class BackorderEntityControllerConverter implements Converter {

        public Object getAsObject(FacesContext facesContext, UIComponent component, String value) {
            if (value == null || value.length() == 0) {
                return null;
            }
            BackorderEntityController controller = (BackorderEntityController) facesContext.getApplication().getELResolver().
                    getValue(facesContext.getELContext(), null, "backorderEntityController");
            return controller.ejbFacade.find(getKey(value));
        }

        java.lang.Long getKey(String value) {
            java.lang.Long key;
            key = Long.valueOf(value);
            return key;
        }

        String getStringKey(java.lang.Long value) {
            StringBuffer sb = new StringBuffer();
            sb.append(value);
            return sb.toString();
        }

        public String getAsString(FacesContext facesContext, UIComponent component, Object object) {
            if (object == null) {
                return null;
            }
            if (object instanceof BackorderEntity) {
                BackorderEntity o = (BackorderEntity) object;
                return getStringKey(o.getId());
            } else {
                throw new IllegalArgumentException("object " + object + " is of type " + object.getClass().getName() + "; expected type: " + BackorderEntityController.class.getName());
            }
        }
    }
}
